#include "gameMer.h"
#include <stdio.h>
#include "../entity/sceneMain.h"
#include "../entity/sceneTitle.h"
#include <SDL.h>
#include <fstream>

int STG::GameMer::init()
{
    //SDL初始化
    if(SDL_Init(SDL_INIT_EVERYTHING) != 0){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"SDL_Init Error: %s\n", SDL_GetError());
        isRunning = false;
        return -1;
    }
    //创建窗口
    window = SDL_CreateWindow("STG", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
    if(window == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"SDL_CreateWindow Error: %s\n", SDL_GetError());
        isRunning = false;
        return -1;  
    }
    //创建渲染器
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if(renderer == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"SDL_CreateRenderer Error: %s\n", SDL_GetError());
        isRunning = false;
        return -1;
    }

    //初始化SDL_image
    if(IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) != (IMG_INIT_PNG|IMG_INIT_JPG)){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"IMG_Init Error: %s\n", IMG_GetError());
        isRunning = false;  
        return -1;
    }

    //初始化SDL_mix
    if(Mix_Init(MIX_INIT_OGG | MIX_INIT_MP3) != (MIX_INIT_OGG | MIX_INIT_MP3)){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"Mix_Init Error: %s\n", Mix_GetError());
        isRunning = false;  
        return -1;
    }

    //打开音频设备
    if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) == -1){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"Mix_OpenAudio Error: %s\n", Mix_GetError());
        isRunning = false;  
        return -1;
    }
    SDL_RenderSetLogicalSize(renderer, width, height);

    //初始化音频
    Mix_AllocateChannels(32);
    Mix_VolumeMusic(MIX_MAX_VOLUME / 2);
    Mix_Volume(-1, MIX_MAX_VOLUME / 2);

    //初始化SDL_ttf
    if(TTF_Init() == -1){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"TTF_Init Error: %s\n", TTF_GetError());
        isRunning = false;
        return -1;
    }
    //初始化字体
    font = TTF_OpenFont("../assets/font/VonwaonBitmap-12px.ttf", 24);
    if(font == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"TTF_OpenFont Error: %s\n", TTF_GetError());
        isRunning = false;
        return -1;
    }
    titleFont = TTF_OpenFont("../assets/font/VonwaonBitmap-16px.ttf", 48);
    if(titleFont == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"TTF_OpenFont Error: %s\n", TTF_GetError());
        isRunning = false;
        return -1;
    }

    //初始化音效
    soundEffect["player_shoot"] = Mix_LoadWAV("../assets/sound/laser_shoot4.wav");
    soundEffect["player_explosion"] = Mix_LoadWAV("../assets/sound/explosion1.wav");
    soundEffect["enemy_explosion"] = Mix_LoadWAV("../assets/sound/explosion3.wav");
    soundEffect["enemy_shoot"] = Mix_LoadWAV("../assets/sound/xs_laser.wav");
    soundEffect["hit"] = Mix_LoadWAV("../assets/sound/eff11.wav");
    soundEffect["get_item"] = Mix_LoadWAV("../assets/sound/eff5.wav");

    //初始化背景
    nearBackground.texture = IMG_LoadTexture(renderer, "../assets/image/Stars-A.png");
    SDL_QueryTexture(nearBackground.texture, nullptr, nullptr, &nearBackground.width, &nearBackground.height);
    nearBackground.width /= 2;
    nearBackground.height /= 2;
    farBackground.texture = IMG_LoadTexture(renderer, "../assets/image/Stars-B.png");
    SDL_QueryTexture(farBackground.texture, nullptr, nullptr, &farBackground.width, &farBackground.height);
    farBackground.width /= 2;
    farBackground.height /= 2;
    nearBackground.speed = 20.0f;
    farBackground.speed = 10.0f;

    //初始化frameTime
    frameTime = static_cast<float>(1000 / FPS);

    //读取得分榜
    loadLeaderBoard();

    //初始化场景
    currentScene = new sceneTitle(); 
    currentScene ->init();        
    return 0;
}

int STG::GameMer::run()
{
    SDL_Event event;
    float deltaTime = 0.0f;
    init();
    while (isRunning)
    {
        auto frameStart = SDL_GetTicks();
        handleEvent(&event);
        update(deltaTime);
        render();
        auto frameEnd = SDL_GetTicks();
        auto diff = frameEnd - frameStart;
        if(diff < frameTime){
            auto delay = static_cast<Uint32>(frameTime) - diff;
            SDL_Delay(delay);
            deltaTime = frameTime / 1000.0f;
        }else{
            deltaTime = diff / 1000.0f;
        }
        //SDL_Log("frameTime: %f frameStart: %u frameEnd: %u diff: %u deltaTime: %f\n", 
        //    frameTime , frameStart, frameEnd, diff, deltaTime);
    }
    clean();
    return 0;
}

int STG::GameMer::changeScene(scene *scene)
{
    if(currentScene!=nullptr){
        currentScene->clean();
        delete currentScene;
    }
    currentScene = scene;
    currentScene->init();
    return 0;
}

int STG::GameMer::handleEvent(SDL_Event *event)
{        
    while (SDL_PollEvent(event))
    {
        switch (event->type)
        {
        case SDL_QUIT:
            isRunning = false;
            break;
        case SDL_KEYDOWN:
            switch (event->key.keysym.scancode)
            {
            case SDL_SCANCODE_F4:
                SDL_Log("F4 Pressed\n");
                if(fullwin){
                    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
                }else{
                    SDL_SetWindowFullscreen(window, 0);
                }
                fullwin = !fullwin;
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }
        currentScene->handleEvents(event);
    }
    return 0;
}

int STG::GameMer::render()
{
    //清屏
    SDL_RenderClear(renderer);

    //绘制背景
    renderBackground();
    
    //绘制场景
    currentScene->render();

    //绘制
    SDL_RenderPresent(renderer);
    return 0;
}

int STG::GameMer::renderBackground()
{
    //绘制远景
    int posY = static_cast<int>(farBackground.offset);
    for(posY; posY < height; posY += farBackground.height){
        for(int posX = 0; posX < width; posX += farBackground.width){
            SDL_Rect dstRect = {posX, posY, farBackground.width, farBackground.height};
            SDL_RenderCopy(renderer, farBackground.texture, nullptr, &dstRect);
        }
    }
    //绘制近景
    posY = static_cast<int>(nearBackground.offset);
    for(posY; posY < height; posY += nearBackground.height){
        for(int posX = 0; posX < width; posX += nearBackground.width){
            SDL_Rect dstRect = {posX, posY, nearBackground.width, nearBackground.height};
            SDL_RenderCopy(renderer, nearBackground.texture, nullptr, &dstRect);
        }
    }
    return 0;
}

SDL_Point STG::GameMer::renderTextCenter(const std::string &text, float posY, bool isTitle)
{
    SDL_Color color = {255,255,255,255};
    SDL_Surface * surface;
    if(isTitle){
        surface = TTF_RenderUTF8_Solid(GameMer::instance()->getTitleFont(),text.c_str(),color);
    }else{
        surface = TTF_RenderUTF8_Solid(GameMer::instance()->getFont(),text.c_str(),color);
    }
    SDL_Texture * texture = SDL_CreateTextureFromSurface(GameMer::instance()->getRenderer(),surface);
    int y = static_cast<int>((height - surface->h) * posY);
    SDL_Rect dst = { width / 2 - surface->w / 2  , y , surface->w , surface->h };
    SDL_RenderCopy(GameMer::instance()->getRenderer(),texture,nullptr,&dst);
    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
    return {dst.x + dst.w, y };
}

void STG::GameMer::renderText(const std::string &text, int posX, int posY , bool isLeft)
{
    SDL_Color color = {255,255,255,255};
    SDL_Surface* surface = TTF_RenderUTF8_Solid(GameMer::instance()->getFont(),text.c_str(),color);
    SDL_Texture * texture = SDL_CreateTextureFromSurface(GameMer::instance()->getRenderer(),surface);
    SDL_Rect dst ;
    if(!isLeft){
        dst = { posX  , posY , surface->w , surface->h };
    }else{
        dst = { width - posX - surface->w , posY , surface->w , surface->h };
    }
    SDL_RenderCopy(GameMer::instance()->getRenderer(),texture,nullptr,&dst);
    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
}

void STG::GameMer::insertLeaderBoard(int score, std::string name)
{
    leaderBoard.insert({score,name});
    if(leaderBoard.size() > 8){
        leaderBoard.erase(--leaderBoard.end());
    }
}

int STG::GameMer::update(float deltaTime)
{
    //printf("game update\n");
    if(deltaTime == 0.0f){
        SDL_Log("deltaTime is 0.0f\n");
        return -1;
    }
    updateBackground(deltaTime);
    currentScene->update(deltaTime);
    return 0;
}

int STG::GameMer::updateBackground(float deltaTime)
{
    nearBackground.offset += nearBackground.speed * deltaTime;
    if(nearBackground.offset >= 0){
        nearBackground.offset -= nearBackground.height;
    }
    farBackground.offset += farBackground.speed * deltaTime;
    if(farBackground.offset >= 0){
        farBackground.offset -= farBackground.height;
    }
    return 0;
}
 
int STG::GameMer::clean()
{
    if(nearBackground.texture != nullptr){
        SDL_DestroyTexture(nearBackground.texture);
    }
    if(farBackground.texture != nullptr){
        SDL_DestroyTexture(farBackground.texture);
    }

    for(auto &it : soundEffect){
        if(it.second != nullptr){
            Mix_FreeChunk(it.second);
        }
    }
    soundEffect.clear();
    
    //清理字体
    TTF_CloseFont(font);
    //清理SDL_ttf
    TTF_Quit();
    //清理音频设备
    Mix_CloseAudio();
    //清理SDL_mixer
    Mix_Quit();
    //清理SDL_image
    IMG_Quit();
    //清理SDL渲染器
    SDL_DestroyRenderer(renderer);
    //清理SDL窗口
    SDL_DestroyWindow(window);
    //清理SDL
    SDL_Quit();
    
    return 0;
}

void STG::GameMer::saveLeaderBoard()
{
    //保存得分榜
    std::ofstream file("leaderboard.dat");
    if(!file.is_open()){
        SDL_Log("open leaderboard.dat failed\n");
        return;
    }
    for(auto &it : leaderBoard){
        file << it.first << " " << it.second << std::endl;
    }
    file.close();

}

void STG::GameMer::loadLeaderBoard()
{
    //加载得分榜
    std::ifstream file("leaderboard.dat");
    if(!file.is_open()){
        SDL_Log("open leaderboard.dat failed\n");
        return;
    }
    leaderBoard.clear();
    int score;
    std::string name;
    while(file >> score >> name){
        leaderBoard.insert({score,name});
    }
    file.close();
}
